/**
 * @Created Sep 13, 2010 1:15:50 PM
 * @author r39
 */
package com.philip.journal.common;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.philip.journal.core.Messages;

/**
 * Date or Time will not be removed, instead toString will display either Date-only or Time-only.
 */
public final class DateUtils {

    /** Rtfc. */
    public static final int MS_PER_MINUTE = 60 * 1000;
    /** Rtfc. */
    public static final int MS_PER_HOUR = 60 * MS_PER_MINUTE;
    /** Rtfc. */
    public static final int MS_PER_DAY = 24 * MS_PER_HOUR;

    /** DateFormat time only. */
    public static final DateFormat DTFMT_TIME_ONLY = new SimpleDateFormat("HH:mm:ss:SSS", Locale.getDefault());

    /** Singleton Class reference. */
    private static final DateUtils INSTANCE = new DateUtils();

    /** Lock object for thread synchronization. */
    private static Object lock = new Object();

    /** Class logger reference. */
    private static Log logger = LogFactory.getLog(DateUtils.class); // NOPMD by r39

    /** Private constructor to enforce Singleton. */
    private DateUtils() {}


    /**
     * Singleton factory method.
     *
     * @return Singleton instance.
     */
    public static DateUtils getInstance()
    {
        return INSTANCE;
    }

    /** Default date format. */
    private static final DateFormat DATE_FORMAT = new SimpleDateFormat("MMddyyyy", Locale.getDefault());

    /**
     * RTFC.
     *
     * @param date Date to retrieve time from.
     * @return Date without the date factored in. null if the date passed is also null.
     */
    public Date toTimeOnly(final Date date)
    {
        return new java.sql.Time(date.getTime());
    }

    /**
     * Remove the time portion of a date.
     *
     * @param date to remove the time from.
     * @return Date without the time. null if the date passed is also null.
     */
    public Date removeTime(final Date date)
    {
        Date retval = null;
        if (date != null) {
            try {
                synchronized (lock) {
                    retval = DATE_FORMAT.parse(DATE_FORMAT.format(date));
                }
            } catch (final ParseException notpossible) {
                logger.fatal(Messages.Error.IMPOSSIBLE);
            }
        }
        return new java.sql.Date(retval.getTime());

    }

    /**
     * date1 - date2, disregard time portion. If difference is only 1 hour but fall on different date, it will still
     * count as 1 day difference.
     *
     * @param date1 - minuend.
     * @param date2 - subtrahend.
     * @return days difference. date1 - date2.
     * @exception IllegalArgumentException when date1 or date2 is null.
     */
    public long getDayDifference(final Date date1, final Date date2)
    {
        if (date1 == null || date2 == null) {
            throw new IllegalArgumentException();
        }
        return (removeTime(date1).getTime() - removeTime(date2).getTime()) / MS_PER_DAY;
    }

    /**
     * TODO: Unit Test.
     *
     * Will ignore the date part.
     *
     * @param date1 - minuend.
     * @param date2 - subtrahend.
     * @return time difference in milliseconds. date1 - date2.
     * @exception IllegalArgumentException when date1 or date2 is null.
     */
    public long getTimeDifference(final Date date1, final Date date2)
    {
        if (date1 == null || date2 == null) {
            throw new IllegalArgumentException();
        }

        long retval = 0;
        try {

            synchronized (lock) {
                retval = DTFMT_TIME_ONLY.parse(DTFMT_TIME_ONLY.format(date1)).getTime()
                        - DTFMT_TIME_ONLY.parse(DTFMT_TIME_ONLY.format(date2)).getTime();
            }
        } catch (final ParseException e) {
            LogFactory.getLog(getClass()).debug(e.getMessage(), e);
        }
        return retval;
    }

}
